# !/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  :users.py
# @Time      :2022/5/27 14:26
# @Author    :张志坤
from common.utils.qiniuyun import qiniu_token
from common.utils.login_utils import login_required
from common.model_fields.user import user_fields, channel_fields, comment_fields
from flask import Blueprint, jsonify, current_app, g
from flask_restful import Api, reqparse, Resource, marshal
from models.user import *
# 导入自己编写的生成token与校验token
from common.utils.jwt_util import generate_jwt, verify_jwt, _generate_token

# 密码哈希加密
from werkzeug.security import generate_password_hash

# 异步发送短信验证码
from common.tasks.send_code import sms_code
import random
import redis
from datetime import datetime, timedelta
from common.utils.user_cache import UserCache

user_bp = Blueprint("user_bp", __name__, url_prefix="/users")

api = Api(user_bp)


class UserRegister(Resource):
    """注册"""

    def post(self):
        """注册"""
        parse = reqparse.RequestParser()
        parse.add_argument('username')
        parse.add_argument('password')
        parse.add_argument('nickname')
        parse.add_argument('mobile')
        parse.add_argument('confirmpassword')
        args = parse.parse_args()

        username = args['username']
        password = args['password']
        nickname = args['nickname']
        mobile = args['mobile']
        confirmpassword = args['confirmpassword']
        print("我是密码", password, confirmpassword)
        # 判断 用户名 和 昵称 是否合规
        if len(username) > 32 or len(nickname) > 32:
            return jsonify(msg="用户名或昵称不符合规范", code=400)

        # 判断两次密码是否一样
        if password != confirmpassword:
            return jsonify(msg="两次输入的密码不一致!!", code=400)
        # 判断手机号是否存在
        user = UserModel.query.filter_by(mobile=mobile).first()
        if user:
            return jsonify(msg="手机号已存在", code=400)
        # 密码加密
        hash_pwd = generate_password_hash(password)
        try:
            # 存入数据   通过模型类添加获得一个对象
            user = UserModel(account=username, password=hash_pwd, user_name=nickname, mobile=mobile)
            # 通过db.session将user对象添加到表中
            db.session.add(user)
            # 然后保存
            db.session.commit()
            # 返回响应
            return jsonify(msg="注册成功", code=200)
        except Exception as e:
            print("注册报错了", e)
            # 返回响应
            return jsonify(msg='注册失败', code=400)


class SendSMSCode(Resource):
    """发送短信验证码"""

    def post(self):
        parse = reqparse.RequestParser()
        parse.add_argument('mobile')
        args = parse.parse_args()
        mobile = args["mobile"]
        print("我是手机号", mobile)
        # 生成验证码
        code = "%s" % random.randint(100000, 999999)
        # 发送验证码
        res = sms_code.delay(mobile, code)
        # print("发送验证码的响应", res)
        if res:
            return jsonify(msg="发送成功,请注意查收", code=200)
        else:
            return jsonify(msg="发送失败,请稍后重试!!", code=400)


class UserLogin(Resource):
    # def _generate_token(self, user, is_refresh=True):
    #     """
    #     生成token
    #     :param user:
    #     :return: token
    #     """
    #     # 获取盐
    #     secret = current_app.config.get('SECRET_KEY')
    #     print('users文件的盐', secret)
    #     # 定义过期时间 datetime.utcnow():得到一个utc时间  拼接过期时间2小时
    #     expiry = datetime.utcnow() + timedelta(seconds=30)
    #     # 生成token   调用自己编写的generate_jwt  方法   返回一个token
    #     # user_data = json.dumps(user)
    #     token = generate_jwt(user, expiry, secret)
    #     print("我是登陆里面的那啥is_refresh", is_refresh)
    #     if is_refresh:
    #         print("我是登陆里面的那啥is_refresh", is_refresh)
    #         # is_refresh作为更新token的信号
    #         expiry = datetime.utcnow() + timedelta(days=15)
    #         refresh_token = generate_jwt(user, expiry, secret)
    #     else:
    #         refresh_token = None
    #     print("刷新生成的token+++++", refresh_token)
    #     return token, refresh_token

    def post(self):
        """根据手机号验证码 登录"""
        parse = reqparse.RequestParser()
        parse.add_argument('mobile')
        parse.add_argument('sms')

        args = parse.parse_args()
        mobile = args['mobile']
        code = args['sms']
        if not all([mobile, code]):
            return jsonify(msg='请补全登录信息', code=400)
        # 判断用户是否存在
        try:
            user = UserModel.query.filter_by(mobile=mobile).first()
            print("判断用户是否存在", user, user.mobile)
        except Exception as e:
            print("用户不存在", e)
            return jsonify(msg="用户手机号不存在", code=400)
        # 判断验证码是否正确
        redis_cli = redis.Redis(db=3)
        try:
            out_code = redis_cli.get(mobile).decode()
        except Exception as e:
            print("验证码错误,没有获取到", e)
            out_code = None
        if code != out_code:
            return jsonify(msg='验证码错误或过期', code=400)
        # 生成token
        try:
            # 返回的时两个token   登陆时不成刷新tokenis_refresh=False
            token, refresh_token = _generate_token({
                "user_id": user.uid
                # 'username': user.account
            }, is_refresh=False)
            print("我是token>>>>", token)
            print("我是refresh_token", refresh_token)
        except Exception as e:
            print("user生成token的错", e)
            return jsonify(msg='服务器错误', code=400)
        return jsonify(msg="登陆成功", code=200, data={"token": token, 'user_id': user.uid, 'refresh_token': refresh_token})

    # def put(self):
    #     """
    #     刷新token
    #     :return:
    #     """
    #     if g.user_id is not None and g.is_refresh is True:
    #         token, refresh_token = self._generate_token(g.user_id, is_refresh=False)
    #         return {'message': 'ok', 'data': {'token': token}}
    #     else:
    #         return {'message': 'Invalid refresh token'}, 403


class UpdateUserInfo(Resource):
    @login_required
    def get(self, id):
        try:
            # user = UserModel.query.filter_by(uid=id).first()
            user = UserCache(id).get()  # 获取缓存中的用户信息
        except Exception as e:
            print("获取用户对象报错:", e)
            return jsonify(msg="用户不存在", code=400)
        # user = marshal(user, user_fields)
        return jsonify(data=user)

    @login_required
    def post(self, id):
        """修改用户信息"""
        parse = reqparse.RequestParser()
        parse.add_argument("password")
        parse.add_argument("nickname")
        parse.add_argument("gender")
        parse.add_argument("profile_photo")

        args = parse.parse_args()
        password = args['password']
        nickname = args['nickname']
        gender = args['gender']
        profile_photo = args['profile_photo']

        if profile_photo:
            try:
                UserModel.query.filter_by(uid=id).update({"profile_photo": profile_photo})
                db.session.commit()
            except Exception as e:
                print("修改头像失败", e)
                return jsonify(msg="修改头像失败", code=400)
            return jsonify(msg="修改头像成功", code=200)
        if password:
            try:
                hash_password = generate_password_hash(password)
                UserModel.query.filter_by(uid=id).update({"password": hash_password})
                # 修改后保存
                db.session.commit()
            except Exception as e:
                print("修改密码报错", e)
                return jsonify(msg="修改密码失败", code=400)

            # 修改成功 生成新的token
            data = {
                "user_id": id
            }
            token, refresh_token = _generate_token(data)
            # 把新生成的token写入redis
            rds = redis.Redis()
            print("修改密码后生成的token", token)
            rds.set("user:%s:token" % id, token, 2 * 60 * 60)
            return jsonify(msg="修改密码成功", code=200,
                           data={'token': token, 'user_id': id, 'refresh_token': refresh_token})

        if nickname:
            try:
                UserModel.query.filter_by(uid=id).update({"user_name": nickname})
                # 修改后保存
                db.session.commit()
            except Exception as e:
                print("修改昵称报错", e)
                return jsonify(msg="修改昵称失败", code=400)
            return jsonify(msg="修改昵称成功", code=200)
        if gender:
            try:
                UserModel.query.filter_by(uid=id).update({"gender": gender})
                # 修改后保存
                db.session.commit()
            except Exception as e:
                print("修改性别报错", e)
                return jsonify(msg="修改性别失败", code=400)
            return jsonify(msg="修改性别成功", code=200)


class UserChannelResource(Resource):
    @login_required
    def get(self):
        """
        获取 用户关注的频道
        1.用户必须登录
        2.根据登录的用户id  查询关注的频道
        :return:
        """
        user_id = g.user_id
        print("我是用户id", user_id)
        try:
            user = UserModel.query.filter_by(uid=user_id).first()
        except Exception as e:
            print("用户不存在", e)
            return jsonify(msg='用户不存在', code=400)
        channels = marshal(user.channels, channel_fields)
        print("频道", channels)
        return jsonify(data=channels)


class CancelUserChannelResource(Resource):
    @login_required
    def get(self, id):
        """取消关注频道"""
        user_id = g.user_id
        print("这是用户id", user_id)
        try:
            UserChannel.query.filter_by(uid=user_id, cid=id).delete()
        except Exception as e:
            print("取消关注的错误", e)
            return jsonify(msg="取消关注失败", code=400)
        db.session.commit()
        return jsonify(msg="取消关注成功", code=200)


class UserRelationResource(Resource):
    @login_required
    def get(self):
        """
        获取 用户关注的用户
        1.用户必须登录
        2.根据登录的用户id  查询关注的用户
        :return:
        """
        user_id = g.user_id
        print("我是用户id", user_id)
        try:
            user = Relation.query.filter_by(user_id=user_id).all()
        except Exception as e:
            print("关注用户不存在", e)
            return jsonify(msg='关注用户不存在', code=400)
        userlist = [UserModel.query.filter_by(uid=i.foller_id).first() for i in user]
        users = marshal(userlist, user_fields)
        print("关注的用户>>>>>>", users)
        return users


class CancelUserRelationResource(Resource):
    @login_required
    def get(self, id):
        user_id = g.user_id
        print("关注用户的用户id", user_id, id)
        try:
            Relation.query.filter_by(user_id=user_id, foller_id=id).delete()
        except Exception as e:
            print("取消关注用户错误", e)
            return jsonify(msg="取消关注失败", code=400)
        db.session.commit()
        return jsonify(msg="取消关注成功", code=200)


class UserResource(Resource):
    @login_required
    def get(self):
        """
        获取 用户收藏...
        1.用户必须登录
        2.根据登录的用户id  查询收藏
        :return:
        """
        user_id = g.user_id
        print("我是用户id", user_id)
        try:
            user = UserModel.query.filter_by(uid=user_id).first()
        except Exception as e:
            print("用户不存在", e)
            return jsonify(msg='用户不存在', code=400)
        userlist = [UserModel.query.filter_by(uid=i.foller_id).first() for i in user]
        users = marshal(userlist, user_fields)
        print("关注的用户>>>>>>", users)
        return users


class UserCommentResource(Resource):
    @login_required
    def get(self):
        """
        获取 用户跟帖
        1.用户必须登录
        2.根据登录的用户id  查询跟帖
        :return:
        """
        user_id = g.user_id
        print("我是用户id", user_id)
        try:
            user = UserModel.query.filter_by(uid=user_id).first()
            print("user", user)
        except Exception as e:
            print("用户不存在", e)
            return jsonify(msg='用户不存在', code=400)
        comment_list = Comment.query.filter_by(user_id=user_id).all()
        print("跟帖内容>>>>>>", comment_list)
        comments = marshal(comment_list, comment_fields)
        return jsonify(data=comments)


class QiniuToken(Resource):
    @login_required
    def get(self):
        """生成七牛云上传的token"""
        token = qiniu_token()
        return jsonify(msg="OK", code=200, data={'token': token})


# 注册
api.add_resource(UserRegister, "/register")
# 发送验证码
api.add_resource(SendSMSCode, "/smscode")
# 登录
api.add_resource(UserLogin, "/login")
# 获取用户信息
api.add_resource(UpdateUserInfo, "/info/<int:id>")
# 关注频道
api.add_resource(UserChannelResource, "/user_channel")
# 取消关注频道
api.add_resource(CancelUserChannelResource, "/user_channel/<int:id>")
# 用户关注用户
api.add_resource(UserRelationResource, "/user_follows")
# 取消关注用户
api.add_resource(CancelUserRelationResource, "/user_unfollow/<int:id>")
# 用户跟贴
api.add_resource(UserCommentResource, "/user_comments")

# 七牛云token
api.add_resource(QiniuToken, "/qiniu_t")

# celery -A common.celery_tasks.main worker -l info -P eventlet
